//! General types.

use aspect_msgqueue::Msg;

/// A batch of messages we want to process all at once.
///
/// The indexes of the messages in the batch are guaranteed to be contiguous,
/// assuming they were inserted honestly.
pub struct MsgBatch {
    first_idx: u64,

    /// The list of messages.
    ///
    /// MUST be contiguous and ordered.
    messages: Vec<Msg>,
}

impl MsgBatch {
    /// Constructs a batch with initially a single message.
    pub fn new_single(first_idx: u64, msg: Msg) -> Self {
        Self {
            first_idx,
            messages: vec![msg],
        }
    }

    /// Returns a slice of messages.
    pub fn messages(&self) -> &[Msg] {
        &self.messages
    }

    /// Returns the index of the first message in the batch.
    pub fn first_idx(&self) -> u64 {
        self.first_idx
    }

    /// Returns the index of the last message in the batch.
    pub fn last_idx(&self) -> u64 {
        self.first_idx + self.messages.len() as u64 - 1
    }

    /// Attempts to add a message for some index, with sanity checking.
    ///
    /// Returns if the message was added to the queue after all.
    pub fn add_message(&mut self, idx: u64, msg: Msg) -> bool {
        if idx != self.last_idx() + 1 {
            return false;
        }

        self.messages.push(msg);
        true
    }

    /// Returns an iterator over the messages in the batch along with their indexes.
    pub fn messages_iter(&self) -> impl Iterator<Item = (u64, &Msg)> {
        self.messages
            .iter()
            .enumerate()
            .map(|(i, m)| (self.first_idx() + i as u64, m))
    }

    pub fn first_ts(&self) -> u64 {
        self.messages.first().unwrap().timestamp()
    }

    pub fn last_ts(&self) -> u64 {
        self.messages.last().unwrap().timestamp()
    }
}
